﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing; //For Color class
using System.Diagnostics;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;

namespace DirectX_CS
{
	
/// <summary>
/// Begin runing standard managed Windows loop. Call ProcessDataChanges() occasionally or when known data changes must occur, such as during a load screen. See Main() in DirectXWindow.cs.
/// Between calls to Device.BeginScene() and Device.EndScene() call RenderPrimitives(). 
///
/// </summary>
public class PrimitiveManager
{

private Device mDevice = null;
private int mIndexBufferPrimitiveCount = 0;
private Dictionary<object, RegistrationInfo> mRegistrations = null;
private List<IRenderCallable> mRenderableOthers = null;

private TextWriterTraceListener debugL = null;
private bool mMaterialManagement = true;

private static PrimitiveManager onlyManager = null;

public static PrimitiveManager OnlyManager
{
	get { return PrimitiveManager.onlyManager; }
	set { PrimitiveManager.onlyManager = value; }
}

public List<object> RegisteredPrimitives
{
	get 
	{
		return mRegistrations.Keys.ToList();
	}
}
	
public bool MaterialManagement
{
	get { return mMaterialManagement; }
	set { mMaterialManagement = value; }
}

public PrimitiveManager()
{
	mDevice = MainProgram.DxDevice;
	onlyManager = this;
    //mDevice.VertexFormat = SVector.Format;//SVector.customVertexFormat;
	mRegistrations = new Dictionary<object, RegistrationInfo>();
	mRenderableOthers = new List<IRenderCallable>();
	debugL = new TextWriterTraceListener(System.Console.Out, "debug main");
    System.Diagnostics.Debug.Listeners.Add(debugL);

}

~PrimitiveManager() //destructor
{
	//let each of my managed companions know that this is on it's death bed...
	foreach (RegistrationInfo pgInfo in GetRegistrations)
	{
		if (pgInfo != null) //in some cases this member will be null (see: bool RegistrationInfo.WasUnRegistered())
		{
			if (pgInfo.VertexBufferObject != null)
				pgInfo.VertexBufferObject.ManagerDestroyed(this);
			//else
				//pgInfo.IndexedBufferObject.ManagerDestroyed(this);
		}
	}

	foreach (IRenderCallable obj in GetRenderCallableRegistrations())
	{
		if (obj != null) //in some cases this member will be null (see: bool RegistrationInfo.WasUnRegistered())
		{
			((IRenderCallable)obj).ManagerDestroyed(this);
		}
	}

	//now delete the list entries
	mDevice = null;
	mIndexBufferPrimitiveCount = 0;
	mRegistrations.Clear();
	mRegistrations = null;
	mRenderableOthers.Clear();
	mRenderableOthers = null;
	onlyManager = null;
}

List<IRenderCallable> GetRenderCallableRegistrations()
{
	return mRenderableOthers.ToList<IRenderCallable>();
}

RegistrationInfo[] GetRegistrationsArray()
{
	if (mRegistrations == null)
		return null;
	else if (mRegistrations.Count == 0)
		return null;
	else
		return mRegistrations.Values.ToArray<RegistrationInfo>();
	
}

/*
/// <summary>
/// Recreate the vertex array in the order the items were made.
/// This method can be called to initialize the structure as well as to maintain it.
/// Note to self: be sure to add references to:
///   InitialLength ScaleFactor 
/// </summary>
private int RecreateVertexRegistrationInfo()
{
	RegistrationInfo[] regInfoList = GetRegistrationsArray(); //primitiveWithVertices registration list
    if (regInfoList == null)
        return 0;

	int newSize = -1;
	bool bWillChangeSize = WillVBChangeSize(regInfoList, out newSize);
    
	///long finalSize = newSize;
    int offsetIndex = 0;
	//remember adding zero to something does no point so sometimes that's easy to forget if you dont see me add a length to the accumulator.
    //NOW CREATE THE DATA...COPY DATA PROCESS
    RegistrationInfo regInfo = null;
        for (int i = 0; i < regInfoList.Length; i++)
        {
            regInfo = regInfoList[i];
            //regInfo.LockOffsetIntoVertexBuffer = offsetIndex;

            if (regInfo == null)
            { //Null pointer. skip past this element; not copying it into the new array
            }
            else
            {
                object vtxData = regInfo.GetVertices();
                //int copyCount = regInfo.GetVerticesCopyCount();
                //regInfo.VertexCopyLength = copyCount;

                if (vtxData != null)
                {
                    if (regInfo.IsInitialized == true)
                    {
                        //Array.Copy(vtxData, 0, aDataIndices, offsetIndex, regInfo.VertexCopyLength);
                        regInfo.CurrentVertexBufferLength = regInfo.VertexCopyLength;
                    }
                    else
                    {
						regInfo.CurrentVertexBufferLength = regInfo.VertexCopyLength;
                    }
                 }
                else //if vtxData == null
                {
                    regInfo.CurrentVertexBufferLength = 0;
                }

                offsetIndex += regInfo.CurrentVertexBufferLength;

                //if (i  + 1 < regInfoList.Length )
                //    offsetIndex++;
            }
        }
    
    return offsetIndex;  //size of data

} //end of procedure.
*/

private void RecreateIndexBuffers()
{

    int dataSize = 0;
    RegistrationInfo[] regInfoList = GetRegistrationsArray();
    if (regInfoList == null)
        return;

    foreach (RegistrationInfo regInfo in regInfoList)
    {
        if (regInfo == null)
        { //Null pointer. skip past this element; not copying it into the new array
        }
        else
        {
			if (regInfo.IndexBufferChanged)
			{
				Array idxData = (Array) regInfo.GetIndices();
				if (idxData != null)
				{	
					Type t= idxData.GetValue(0).GetType();
					bool b16Bit = t == typeof(Int16);

					int indicesCount = regInfo.IndexedBufferObject.GetIndicesCount();
					//regInfo.IndexBuffer = new IndexBuffer(mDevice, indicesCount, Usage.Points, Pool.Managed, b16Bit);
					regInfo.IndexBuffer = new IndexBuffer(t, indicesCount, mDevice, Usage.Points, Pool.Managed);
					mDevice.VertexFormat = regInfo.VertexBufferObject.VertexFormat;

					regInfo.IndexPersistantBuffer = (Array)regInfo.IndexBuffer.Lock(0, LockFlags.ReadOnly);
					Array.Copy(idxData, regInfo.IndexPersistantBuffer, indicesCount);
					//regInfo.IndexBuffer.Unlock();
					regInfo.IndexBuffer.SetData(idxData, 0, LockFlags.ReadOnly);    //was accidnentally setting the entire buffer mVertexBuffer

					dataSize += indicesCount;
					regInfo.IsIBInitialized = true;
					regInfo.IndexBufferChanged = false;
					regInfo.IndexCopyLength = indicesCount;
					regInfo.CurrentIndexBufferLength = indicesCount;
					//offsetIndex += regInfo.CurrentIndexBufferLength;
				}
				else
				{
					regInfo.IsIBInitialized = true;
					regInfo.IndexBufferChanged = false;
					regInfo.IndexCopyLength = 0;
					regInfo.CurrentIndexBufferLength = 0;
				}

			}
        }
    }

}


/*

/// <summary>
/// In the future this will give a diagnostic approach to 
/// and allow you to change the array easier, more efficiently,
/// I guess conveniently and with less overhead and waste.
/// </summary>
/// <param name="regInfoList"></param>
/// <returns></returns>
public bool WillVBChangeSize(RegistrationInfo[] regInfoList, out int newSize)
{
	if (regInfoList == null || (regInfoList.Count() == 0) ) //obviously false since it has no size or structure, could check before calling
	{
		newSize = 0;
		return false;
	}

    bool willChange = false; //used to be called: "willChangeSizeOrStructure"
	//bool containsNulls = false;
	//long sizeOfUnregisteredDataAccum = 0; //try to minimize this size
	//see if we can use the same memory, if not set WillEnlarge = true;
	///Loop through each element.

	int offsetIndexDataCount = 0;
	for  (int i = 0; i < regInfoList.Length; i++)
	{
        //if (willChange) 
        //    break;
        RegistrationInfo regInfo = regInfoList[i];
		int dataLength = regInfo.VertexBufferObject.GetVerticesCount(); 
        if (regInfo != null) //same as WasUnRegistered? if null pointer, does not add to buffer size, in fact if its recreated the data will be salvaged.
        {
            //Also remember in subsequent upgrades to check if (regInfo.IndexBufferChanged == true)
            //Check for possible size changes in data.
            if (regInfo.VertexBufferChanged)
            {
                if (regInfo.IsInitialized == false)
                {
                    object vertexArray = regInfo.GetVertices();
					offsetIndexDataCount += dataLength;
                    willChange = true;
                }
                else if (regInfo.VertexCopyLength <= regInfo.CurrentVertexBufferLength) //changing from nonzero size to 0... getting smaller...
                {
                    //willChange = false;
					offsetIndexDataCount += dataLength; //should check if zero
                }

            }
            else //if  (regInfo.VertexBufferChanged = false) 
            {
                if (regInfo.IsInitialized == false)
                {
                    object vertexArray = regInfo.GetVertices();
                    willChange = true;
					offsetIndexDataCount += dataLength;
                }
                else
                    offsetIndexDataCount += regInfo.CurrentVertexBufferLength;
            }
            //if (i + 1  < regInfoList.Length )
            //    offsetIndexDataCount++;
        }//end of if#1
	} //end of for loop.

	///If it made it this FAR, 
	///and it returns true then the data size per piece of new data is less than or equal to its current size, 
	///for sure. 
    Debug.WriteLine("computed size set: " + offsetIndexDataCount);
    Debug.Flush();
    newSize = offsetIndexDataCount;

	return willChange;
} //end of procedure.
*/

/*
/// <summary>
/// In the future this will give a diagnostic approach to 
/// and allow you to change the array easier, more efficiently,
/// I guess conveniently and with less overhead and waste.
/// </summary>
/// <param name="regInfoList"></param>
/// <returns></returns>
public bool WillIBChange(RegistrationInfo[] regInfoList, out int newSize)
{
	if (regInfoList == null || (regInfoList.Count() == 0)) //obviously false since it has no size or structure, could check before calling
	{
		newSize = 0;
		return false;
	}

	bool willChange = false; 
	//int sizeOfUnregisteredDataAccum = 0; //try to minimize this size

	//See if we can use the same memory, if not set willChange = true;
	///Loop through each element.

	int offsetIndexDataCount = 0;
    for (int i = 0; i < regInfoList.Length; i++ )
    {
        RegistrationInfo regInfo = regInfoList[i];
        if (regInfo != null) //same as WasUnRegistered? if null pointer, does not add to buffer size, in fact if its recreated the data will be salvaged.
        {
            object indexdata = null;

            if (regInfo.IndexedBufferObject != null)
            {
                //just because its registered doesnt mean it has data
                indexdata = regInfo.IndexedBufferObject.GetIndices();

				int indexDataLength = regInfo.IndexedBufferObject.GetIndicesCount();
				if (regInfo.IndexCopyLength <= indexDataLength) //todO: In the future check if regInfo.IndexCopyLength >= copyCount, if so just copy data dont recrreate
                {
                    willChange = true;
                }

            }

            //Also remember in subsequent upgrades to check if (regInfo.IndexBufferChanged == true)
            //Check for possible size changes in data.
            if (regInfo.IndexBufferChanged)
            {                 //just because its registered doesnt mean it has data
                indexdata = regInfo.IndexedBufferObject.GetIndices();
				int indexDataLength = regInfo.IndexedBufferObject.GetIndicesCount();
                if (indexdata == null) //New data is null which is ok, just zero data for bufferless--varies for buffered.
                {
                    //data can grow smaller so check this
					if (regInfo.CurrentIndexBufferLength < indexDataLength) //changing from nonzero size to 0... getting smaller...
                    {
                        willChange = true;
						offsetIndexDataCount += indexDataLength;
                    }
                }
                else
                {
                    if (indexdata == null)
                    {
                        regInfo.CurrentIndexBufferLength = 0;
                    }
                    else
                    {
                        regInfo.CurrentIndexBufferLength = regInfo.IndexCopyLength;
                    }

                    //data is nonzero, and it could have grown big or small.
                    if (indexDataLength > regInfo.CurrentIndexBufferLength)
                    {
                        willChange = true;
                    }
					else if (indexDataLength == regInfo.CurrentIndexBufferLength)
                    {

                    }
                    else//else it grew smaller
                    {

                    }
                }

                if (indexdata != null)
                {
					offsetIndexDataCount += indexDataLength;
                    //if (i + 1 < regInfoList.Length )
                    //    offsetIndexDataCount++;
                }

            }
            else
            { //Vertex buffer didnt change. 
            }
        }
    } //end of for loop.

	///If it made it this FAR, 
	///and it returns true then the data size per piece of new data is less than or equal to its current size, 
	///for sure. 
	newSize = offsetIndexDataCount;
	return willChange;
} //end of procedure.
 */
private void ReCreateVBAndSetData(RegistrationInfo regInfo, ref Array vtxData, int dataLength)
{

		if (regInfo.VertexBuffer != null)
		{
			regInfo.VertexBuffer.Dispose();
			regInfo.VertexBuffer = null;
		}
		if (vtxData == null)
		{
			regInfo.VertexBuffer = null;
			return;
		}
		else
		{
			try
			{
				Type vertexType = vtxData.GetValue(0).GetType();
				IManagedVertexBuffer imvb = regInfo.VertexBufferObject;

				GC.Collect();
				VertexBuffer vb = new VertexBuffer(vertexType, dataLength, mDevice, Usage.Points | Usage.Dynamic, imvb.VertexFormat, Pool.Default);
				//VertexBuffer vb = new VertexBuffer(vertexType, dataLength, mDevice, Usage.Points, imvb.VertexFormat, Pool.Managed);//mDevice.GetStreamSource(regInfo.StreamNumber, out offsetInBytes, out stride);

				//int[] ranks = new int[] { dataLength };
				//discard the vertex buffer every time, hence dynamic
				regInfo.VertexPersistantBuffer = vb.Lock(0, LockFlags.Discard);//(0, vertexType, LockFlags.ReadOnly, ranks);


				int i = 0; //idx


				if (regInfo.UseManagedModelView)
				{
					IManagedModelTransformable mv = (IManagedModelTransformable)regInfo.PrimitiveObject;

					if (mv.ModelView != null)
					{
						Matrix modelViewMatrix = mv.ModelView.RecreateMatrix();
						foreach (SVector sv in (Array)vtxData)
						{
							SVector newSV = sv;
							Vector3 newPos = sv.Position; //start with old and in with newpos.
							newPos.TransformCoordinate(modelViewMatrix);
							newSV.Position = newPos;
							regInfo.VertexPersistantBuffer.SetValue(newSV, i);
							i++;
						}

					}

						//}
						//else
						//{
						//    foreach (SVector sv in (Array)vtxData)
						//    {
						//        regInfo.VertexPersistantBuffer.SetValue(sv, i);
						//        i++;
						//    }
						//}
				}
				else
				{
					foreach (SVector sv in (Array)vtxData)
					{
						regInfo.VertexPersistantBuffer.SetValue(sv, i);
						i++;
					}
				}
				//Array.Copy((Array)vtxData, regInfo.VertexPersistantBuffer, dataLength);

				//may have been causing errors
				//VertexDeclaration vertexDeclaration = new VertexDeclaration(mDevice, regInfo.VertexBufferObject.VertexElements); 

				//mDevice.SetStreamSource(0, vb, 0);
				//mDevice.VertexFormat = imvb.VertexFormat;

				//vb.SetData(vtxData, 0, LockFlags.ReadOnly);

				vb.Unlock();	//do not call this it unsets the data for some reason... i guess until locked.

				regInfo.VertexBuffer = vb;
			}
			catch (OutOfMemoryException e)
			{
				debugL.WriteLine("Out of memory.. cannot set vertex buffer for object " + regInfo.PrimitiveObject.GetType().FullName.ToString());
				//System.GC.ReRegisterForFinalize();
				regInfo.VertexPersistantBuffer = null;
				System.GC.Collect();
			}
			catch (OutOfVideoMemoryException e)
			{
				if (regInfo.VertexBuffer != null)
					regInfo.VertexBuffer.Dispose();

				regInfo.VertexPersistantBuffer = null;
				regInfo.VertexBuffer = null;
				System.GC.Collect();
			}
			finally
			{
			}

		}


}
private void SetData(RegistrationInfo regInfo, ref object vtxData, int dataLength)
{
	//int[] ranks = new int[] { dataLength };
	VertexBuffer vb = regInfo.VertexBuffer;
	//regInfo.VertexPersistantBuffer = vb.Lock(0, LockFlags.ReadOnly);//(0, vertexType, LockFlags.ReadOnly, ranks);

	//Array.Copy((Array)vtxData, regInfo.VertexPersistantBuffer, dataLength);

	//may have been causing errors
	//VertexDeclaration vertexDeclaration = new VertexDeclaration(mDevice, regInfo.VertexBufferObject.VertexElements); 

	//mDevice.SetStreamSource(0, vb, 0);
	//mDevice.VertexFormat = imvb.VertexFormat;
	vb.SetData(vtxData, 0, LockFlags.Discard);
	vb.Unlock();
}
	//int[] ranks = new int[] { dataLength };
	//Type vertexType = ((System.Array)vtxData).GetValue(0).GetType();
	//Array lockedData = regInfo.VertexBuffer.Lock(0, vertexType, LockFlags.ReadOnly, ranks);
	//Array.Copy((Array)vtxData, lockedData, dataLength);
	
	//may have been causing errors
	//VertexDeclaration vertexDeclaration = new VertexDeclaration(mDevice, regInfo.VertexBufferObject.VertexElements); 


	//int[] ranks = new int[] { dataLength };
	//regInfo.VertexPersistantBuffer = regInfo.VertexBuffer.Lock(0, LockFlags.ReadOnly);//(0, vertexType, LockFlags.ReadOnly, ranks);
	//Array.Copy((Array)vtxData, regInfo.VertexPersistantBuffer, dataLength);
	//regInfo.VertexPersistantBuffer.SetData(vtxData, 0, LockFlags.ReadOnly);


	//mDevice.VertexFormat = regInfo.VertexBufferObject.VertexFormat;
	//regInfo.VertexBuffer.SetData(vtxData, 0, LockFlags.ReadOnly);
	//regInfo.VertexBuffer.Unlock();
//}

/// <summary>
/// Force re-creation of vertex buffer right this instant. Use sparingly...
/// The method can be called without an instance of a primitiveWithVertices Generator
/// </summary>
private void RecreateVertexBuffers()
{

    /// Note to self: be sure to check for PG==null in the RegistrationInfo which means get rid of it after next data generation.
    //mVertexBuffer = new VertexBuffer(typeof(SVector), bufferSize, mDevice, Usage.Points, SVector.Format, Pool.Managed);


    //ONE IMPORTANT PART IS SETTING THE STREAM SOURCE...
    //I'm surprised its still used because I thought Streams were phased out in .NET
    //however I happen to think that it still needs to get done in unmanaged code,
    //possibly because of the fact it doesn't seem like DirectX is really
    //used alot by Developers (yet) on the .NET platform.
    //int offsetInBytes = 0;
    //mDevice.SetStreamSource(streamNumber, mVertexBuffer, offsetInBytes);

    int dataSize = 0;
    RegistrationInfo[] regInfoList = GetRegistrationsArray();
    if (regInfoList == null)
        return;

    //NOW CREATE THE DATA...COPY DATA PROCESS
    foreach (RegistrationInfo regInfo in regInfoList)
    {
        if (regInfo == null)
        { //Null pointer. skip past this element; not copying it into the new array
			continue;
        }
		else if (regInfo.VertexBufferChanged)
		{
			Array vtxData = regInfo.GetVertices();
			int dataLength;
			if (vtxData == null)
				dataLength = 0;
			else
			{
				dataLength = regInfo.VertexBufferObject.GetVerticesCount();
			}

			if (vtxData != null)
			{
				ReCreateVBAndSetData(regInfo, ref vtxData, dataLength);


				//GraphicsStream lockedData = regInfo.VertexBuffer.Lock(0, 0, LockFlags.ReadOnly);
				//lockedData.Write(vtxData);
				//Array lockedData = regInfo.VertexBuffer.Lock(0, LockFlags.None); 
				//regInfo.VertexBuffer.Unlock(); //use the 3 parameter form not the two so you dont accidentally use the lockflag as an offset.

				//below is an alternate means to doing this
				//GraphicsStream gStream = regInfo.VertexBuffer.Lock(0, 0, LockFlags.None);
				//gStream.Write(vtxData);
				//regInfo.VertexBuffer.Unlock();

				//  regInfo.VertexBuffer.SetData(vtxData, 0, LockFlags.ReadOnly);   

				//byte usageTypeIndex = 0;
				//short offset = 0;
				//mDevice.SetStreamSource(0, regInfo.VertexBuffer, (int)offset);

				/*
				VertexElement positionElement = new VertexElement(0, 0, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.PositionTransformed, usageTypeIndex);
				VertexElement colorElement = new VertexElement(0, 16, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, usageTypeIndex);
				VertexElement[] v = new VertexElement[] 
				{ 
					positionElement,
					colorElement    
				};
				VertexDeclaration decl = new VertexDeclaration(mDevice, v);
				*/

				//to set the entire buffer put in a zero for second arg.
				int dataCount = dataLength;
				dataSize += dataCount;
				regInfo.CurrentVertexBufferLength = dataCount;
				regInfo.VertexCopyLength = dataCount;
			}
			else
			{
				//regInfo.IsInitialized = false; do not alter because the data might aleady be initialized and just null
				regInfo.CurrentVertexBufferLength = 0;
				regInfo.VertexCopyLength = 0;
			}

			regInfo.IsInitialized = true;
			regInfo.VertexBufferChanged = false;
		}
	}
    //dataSize--;

    Debug.WriteLine("size of copied data: " + dataSize);
    Debug.Flush();
}

private bool suppressRecreateBuffers = false;

public bool SuppressRecreateBuffer
{
	get { return suppressRecreateBuffers; }
	set
	{
		suppressRecreateBuffers = value;
		if (value == false) //false for setting all at the same time
		{
            //order matters
            RecreateVertexBuffers(); //call RecreateVertexArray before hand
            //dont call create index buffers first, i think it might mess up.
		    RecreateIndexBuffers();
		}
	}
}

//public bool RegisterPrimitive(object primGen)
//{
//    RegisterPrimitive(primGen, false, false);
//}
//public bool RegisterPrimitive(object primGen, bool callVertexRender, bool callIndexRender)
//{
//    bool primRegistered = RegisterPrimitive(primGen);
//    if (primRegistered)
//    {
//        SetVertexRenderingEnabled(primGen, callVertexRender);
//        SetIndexRenderingEnabled(primGen, callIndexRender);
//    }
//    return primRegistered;
//}
//public void SetVertexRenderingEnabled(object primGen, bool enabled)
//{
//    if (IsRegistered(primGen))
//    {
//        RegistrationInfo regInfo = mRegistrations[primGen];
//        regInfo.VertexRenderingEnabled = enabled;
//    }
//}
//public void SetIndexRenderingEnabled(object primGen, bool enabled)
//{
//    if (IsRegistered(primGen))
//    {
//        RegistrationInfo regInfo = mRegistrations[primGen];
//        if (enabled == true)
//        {
//            if (regInfo.IndexedBufferObject == null)
//            {
//                throw new Exception("Cannot Set Index Rendering to Enabled. Object needs to implement IManagedIndexBuffer.");
//            } else
//            {
//                regInfo.IndexRenderingEnabled = true;
//            }
//        }
//        else
//        {
//            regInfo.IndexRenderingEnabled = false;
//        }

//    }
//}

public static bool Register(object primGen)
{
	if (onlyManager != null)
	{
		return onlyManager.RegisterPrimitive(primGen);
	}
	else
		throw new NullReferenceException();
}
private bool RegisterPrimitive(object primGen)
{
	if (primGen == null)
		return false;

	RegistrationInfo theInfo = null;			
	bool foundPrim = mRegistrations.TryGetValue(primGen, out theInfo);
	
	//check if they are reregistering by supplying a PG already in the list
	if (foundPrim) //if we found pg registered
	{
		System.Diagnostics.Debug.WriteLine("You registered your Primitive Generator twice. Re-registering is not yet supported.");
		return false;
	}
	else
	{
		theInfo = new RegistrationInfo(primGen);
        bool ManagedMaterialInterfaceFound = primGen is IManagedMaterial;
        theInfo.UseManagedMaterial = ManagedMaterialInterfaceFound;

        bool SimpleModelViewFound = primGen is IManagedModelTransformable;
        theInfo.UseManagedModelView = SimpleModelViewFound;

        bool VertexBufferInterfaceFound = primGen is IManagedVertexBuffer;
        if (VertexBufferInterfaceFound)
        {
            theInfo.VertexBufferChanged = true;
            theInfo.VertexBufferObject = (IManagedVertexBuffer)primGen;
        }
        bool IndexBufferInterfaceFound = primGen is IManagedIndexBuffer;
        if (IndexBufferInterfaceFound)
        {
            theInfo.VertexBufferChanged = true;
            theInfo.IndexBufferChanged = true;

            theInfo.IndexedBufferObject = (IManagedIndexBuffer)primGen;
            //theInfo.IndexedBufferObject.VertexBufferChanged += new VBChangedDelegate(VertexBufferObject_VertexBufferChanged);
            mIndexBufferPrimitiveCount++;
       }

		bool RenderableInterfaceFound = primGen is IRenderCallable;
		if (RenderableInterfaceFound)
		{
			IRenderCallable rc = (IRenderCallable)primGen;
			bool alreadyExists = mRenderableOthers.Contains(rc);
			if (!alreadyExists)
				mRenderableOthers.Add(rc);
			else
				Debug.WriteLine("RegisterPrimtive: Cannot add object more than once.");

		}
		

		if (theInfo.VertexBufferObject == null && RenderableInterfaceFound == false)
		{
			throw new Exception("Object " + primGen.ToString() + " must implement a vertex buffer or IRenderCallable!");
		}
		else
		{
			if (VertexBufferInterfaceFound)
				theInfo.VertexBufferObject.VertexBufferChanged += new VBChangedDelegate(VertexBufferObject_VertexBufferChanged);
			if (IndexBufferInterfaceFound)
				theInfo.IndexedBufferObject.IndexBufferChanged += new IBChangedDelegate(IndexedBufferObject_IndexBufferChanged);

			//be sure to set these important properties
			theInfo.PrimitiveObject = primGen;
			mRegistrations.Add(primGen, theInfo);
		}

	}

	return true;//success
}

void IndexedBufferObject_IndexBufferChanged(object sender, int numberOfIndices)
{
	//lets check how much it changed
	RegistrationInfo regInfo = null;
	try
	{
		regInfo = mRegistrations[sender];
	}
	catch (Exception ex)
	{
		throw new PrimitiveNotRegisteredException(sender);
	}
    IndexBufferChanged(regInfo);

}

private void IndexBufferChanged(RegistrationInfo regInfo)
{
	if (suppressRecreateBuffers)
	{
		regInfo.IndexBufferChanged = true;
		regInfo.IsIBInitialized = false;
	}
	else
	{

		bool recreateBuffer = false;
		object indexData = regInfo.GetIndices();
		if (indexData == null)
		{
			regInfo.IndexCopyLength = 0;
			return;
		}

		int copyLength = regInfo.IndexedBufferObject.GetIndicesCount();
		regInfo.IndexCopyLength = copyLength;

		if (copyLength > regInfo.CurrentIndexBufferLength || (regInfo.IsIBInitialized == false))
		{
			recreateBuffer = true;
		}
		else if (regInfo.IsIBInitialized == true)
		{
			recreateBuffer = false;
		}

		if (recreateBuffer && !suppressRecreateBuffers)
		{
			regInfo.IndexBuffer = new IndexBuffer(typeof(int), copyLength, mDevice, Usage.Points, Pool.Default);
			regInfo.IndexBuffer.SetData(indexData, 0, LockFlags.None);    //was accidnentally setting the entire buffer mVertexBuffer

			regInfo.IndexCopyLength = copyLength;
			regInfo.CurrentIndexBufferLength = copyLength;
			regInfo.IndexBufferChanged = false;
			regInfo.IsIBInitialized = true;
		}
		else if (!recreateBuffer && !suppressRecreateBuffers)
		{
			regInfo.IndexBuffer.SetData(indexData, 0, LockFlags.None);

			regInfo.IndexCopyLength = copyLength;
			regInfo.CurrentIndexBufferLength = copyLength;
			regInfo.IndexBufferChanged = false;
			regInfo.IsIBInitialized = true;
		}
	}
}


void VertexBufferObject_VertexBufferChanged(object sender, int numberOfVertices)
{
	//lets check how much it changed
	RegistrationInfo regInfo = null;

		try
		{

			regInfo = mRegistrations[sender];
		}
		catch (Exception ex)
		{
			//dont throw an exception it happens if the thing got unregistered but is still in memmory somewhere... not yet out of the flow of things.
			//but return
			return;
		}
	
		if (suppressRecreateBuffers)
		{
			regInfo.IsInitialized = false;
			regInfo.VertexBufferChanged = true;
		}
		else //if (!suppressRecreateBuffers)
		{
			regInfo.VertexCopyLength = numberOfVertices;

			Array vertexData = regInfo.GetVertices();
			int dataLength;
			if (vertexData == null)
				dataLength = 0;
			else
				dataLength = regInfo.VertexBufferObject.GetVerticesCount();

			int dataCount = dataLength;

			if ((vertexData == null && numberOfVertices != 0) || (numberOfVertices < 0 || numberOfVertices > dataLength))
				throw new Exception("Copy count " + numberOfVertices.ToString() + " of " + regInfo.PrimitiveObject.ToString() + "cannot be greater than the data size.");

			bool recreateBuffer = false;
			if (dataLength > regInfo.CurrentVertexBufferLength || regInfo.IsInitialized == false)
			{
				recreateBuffer = true;
			}

			if (recreateBuffer && !suppressRecreateBuffers)
			{
				//regInfo.VertexBuffer = new VertexBuffer(typeof(SVector), dataLength, mDevice, Usage.Dynamic, SVector.Format, Pool.Default);//mDevice.GetStreamSource(regInfo.StreamNumber, out offsetInBytes, out stride);
				//regInfo.VertexBuffer.SetData(vertexData, 0, LockFlags.None);
				ReCreateVBAndSetData(regInfo, ref vertexData, dataLength);

				regInfo.CurrentVertexBufferLength = dataCount;
				regInfo.VertexBufferChanged = false;
				regInfo.IsInitialized = true;
			}
			else if (!recreateBuffer && !suppressRecreateBuffers)
			{
				//if (regInfo.VertexBuffer == null)
				ReCreateVBAndSetData(regInfo, ref vertexData, dataLength);
				//SetData(regInfo, ref vertexData, dataLength);

				regInfo.CurrentVertexBufferLength = dataCount;
				regInfo.VertexBufferChanged = false;
				regInfo.IsInitialized = true;
				regInfo.VertexCopyLength = numberOfVertices;
			}

		}

}

public static void Unregister(object primGen)
{
	if (onlyManager != null)
		onlyManager.UnregisterPrimitive(primGen);
}

public void UnregisterPrimitive(object primGen)
{
	if (primGen == null) return;

	RegistrationInfo theInfo;
	try
	{
		bool found = mRegistrations.TryGetValue(primGen, out theInfo);

		if (theInfo == null)
		{
			//probably  alrady unregistered, its safe to call twice.
		}
		else
		{
			if (theInfo.IndexedBufferObject != null)
				mIndexBufferPrimitiveCount--;

			//take out primGen from list of primitiveWithVertices Generators
			mRegistrations.Remove(primGen);
		}

		if (primGen is IRenderCallable)
			mRenderableOthers.Remove((IRenderCallable)primGen);

		//if (primGen is IDisposable)
		//{
		//    ((IDisposable)primGen).DisposeInstance();
		//}
	}
	catch (Exception ex)
	{				
	
	}//end try-catch
   
}

public bool IsRegistered(object primGen)
{
    RegistrationInfo theInfo;
    bool found = mRegistrations.TryGetValue(primGen, out theInfo);
    return found;
}

private static bool ITypeFilter(Type t, Object obj)
{
	string objectTypeString = obj.ToString();
	string typeTypeString = t.ToString();
	if (objectTypeString == typeTypeString)
		return true;
	else
		return false;
}

private bool ImplementsType(object o, Type t)
{
	System.Reflection.TypeFilter filterRenderables = new System.Reflection.TypeFilter(ITypeFilter);
	Type[] iList = o.GetType().FindInterfaces(filterRenderables, t);
	if (iList.Contains(t))
		return true;
	else 
		return false;
}

//private void Transform(IManagedModelView rh , RegistrationInfo regInfo)
//{
//    regInfo.PreModelTransform = mDevice.Transform.World;
//    Matrix modelMatrix = mDevice.Transform.World; //create a copy
//    modelMatrix.Translate(rh.Position);
//    //float yawy = 0, pitchx = 0, rollz = renderable.Roll;
//    //modelMatrix.RotateYawPitchRoll(yawy, pitchx, rollz);
//    mDevice.Transform.World = modelMatrix ;
//}

//private void PostModelTransform (IManagedModelView rh, RegistrationInfo reg)
//{
//    mDevice.Transform.World = reg.PreModelTransform;
//}

/// <summary>
/// Since each primitiveWithVertices should for diversity be in charge of its own representation
/// in rendering, although the memory will be managed.
/// </summary>
/// 
public void DoManagedRender()
{

	bool matManagement = MaterialManagement;
	
	Material oldMaterial = mDevice.Material;

	//temporary fix
	mDevice.SetTexture(0, null);

	bool materialChanged = false;

	//&& !SuppressRecreateBuffer
	if (mDevice != null) //presumably only happens a few times during startup if at all.
	{
		List<IRenderCallable> rcs = GetRenderCallableRegistrations();

		foreach (IRenderCallable r in rcs)
		{
			if (r.PreRenderEnabled)
				r.PreRender();
		}
		foreach (RegistrationInfo r in GetRegistrations)
		{
			bool isInit = r.IsInitialized;
			bool bVBRendering = r.VertexRenderingEnabled;
			bool bIBRendering = r.IndexRenderingEnabled;

			if (r != null && r.CurrentVertexBufferLength != 0 && isInit && (bVBRendering || bIBRendering))
			{

				if (matManagement)
				{
					if (r.UseManagedMaterial)
					{
						Material theMaterial = ((IManagedMaterial)r.PrimitiveObject).Material;
						if (theMaterial != null)
						{
							mDevice.Material = theMaterial;
							materialChanged = true;
						}
					}
					else
					{
						if (materialChanged)
						{
							mDevice.Material = oldMaterial;
							materialChanged = false;
						}
					}
				}


				if (isInit)
				{
					if (bVBRendering || bIBRendering)
					{
						mDevice.VertexFormat = r.VertexBufferObject.VertexFormat;//SVector.customVertexFormat;
						//do data stuff and render messages
						mDevice.SetStreamSource(0, r.VertexBuffer, 0);
					}

					if (bVBRendering)
					{
						//rnd.VertexBufferObject.RenderPrimitives(this, rnd.LockOffsetIntoVertexBuffer, rnd.CurrentVertexBufferLength);
						r.VertexBufferObject.RenderPrimitives(this, r.CurrentVertexBufferLength);
					}

					if (r.IsIBInitialized && bIBRendering)
					{
						//    rnd.VertexBufferObject.RenderPrimitives(this, rnd.CurrentVertexBufferLength);
						mDevice.Indices = r.IndexBuffer;
						r.IndexedBufferObject.RenderIndexedPrimitives(this, r.CurrentVertexBufferLength, r.CurrentIndexBufferLength);
					}
				}
			}
		} //end for each

		if (matManagement)
			mDevice.Material = oldMaterial;

		foreach (IRenderCallable r in rcs)
		{
			if (r.PostRenderEnabled)
				r.PostRender();
		}
	}
}
public List<RegistrationInfo> GetRegistrations
{
	get { return mRegistrations.Values.ToList<RegistrationInfo>(); }
}

//OLD CODE
#region "Old Code"

    //private bool autoRenderingEnabled = true;

//public bool AutoRenderingEnabled
//{
//    get { return autoRenderingEnabled; }
//    set { autoRenderingEnabled = value; }
//}

//private void ReSetAllVBData(int lockOffset)
//{
//    mVertexBuffer.Unlock(); //use the 3 parameter form not the two so you dont accidentally use the lockflag as an offset.
//    mVertexBuffer.SetData(aDataVertices, 0, LockFlags.ReadOnly); //0 for all; makes sense.
//    mVertexBuffer.Lock(lockOffset, 0, LockFlags.ReadOnly);//0 for all; makes sense. Be sure this gets done after setting data.
//}

    /*
private void ReSetVBData(RegistrationInfo regInfo, int copyCount)
{
    SVector[] vtxData = null;


    vtxData = regInfo.GetVertices();

    //Array.Copy(vtxData, 0, aDataIndices, offsetIndex, regInfo.VertexCopyLength);
    if (copyCount <= vtxData.Length)
    {
        //now Set the buffer data..
        //set data it seems immediately before calls to lock
       
        // mVertexBuffer.SetData(vtxData, regInfo.LockOffsetIntoVertexBuffer, LockFlags.ReadOnly);

        int iLockOffset = (int)regInfo.LockOffsetIntoVertexBuffer;
        Array lockedData = mVertexBuffer.Lock(iLockOffset, typeof(SVector), LockFlags.None, new int[] { copyCount }); //be sure this gets done after setting data.

        //should try to write up to copy length no more, currently does the whole buffer length.
        //mVertexBuffer.SetData(iLockOffset, iLockOffset, LockFlags.ReadOnly);

        Array.Copy(vtxData, lockedData, copyCount);
        mVertexBuffer.Unlock(); //use the 3 parameter form not the two so you dont accidentally use the lockflag as an offset.
         
        
    }
    else
        throw new Exception("Copy count > data length in " + regInfo.ToString());
	
}    */     
//public bool RegisterPrimitive(PrimitiveGenerator primGen, long initialLength, long BufferGrowthFactor)
//{
//    return RegisterPrimitive(primGen, initialLength, BufferGrowthFactor, false);
//}
//public bool RegisterPrimitive(PrimitiveGenerator primGen, bool UseExactLength)
//{
//    return RegisterPrimitive(primGen, 0, 0, true);
//}
    ///// <summary>
    ///// Usually called by a PrimitiveGenerator class with "this" as the parameter.
    ///// Do not create immediately, create buffer for all primitivegenerators at once, 
    ///// but this signals eventually that we will recreate the vertex buffer by calling CreateNewVertexBuffer.
    ///// </summary>
    ///// <param name="primGen"></param>
    //private void VertexBufferChanged(RegistrationInfo regInfo)
    //{
    //    //if (!suppressRecreateBuffers) //primGen doesnt differentiate between calls when there is no data.
    //    //{
    //        if (aDataVertices != null && aDataVertices.Length != 0)
    //        {
    //            if (regInfo.VertexCopyLength > regInfo.CurrentVertexBufferLength)
    //            {

    //                //regInfo.VertexData = regInfo.IndexedBufferObject.GetVertices();

    //                //just because its registered doesnt mean it has data
    //                //int newCount;
    //                //if (regInfo.VertexBufferObject == null)
    //                //{
    //                //    newCount = regInfo.IndexedBufferObject.GetVerticesCount();
    //                //}
    //                //else    //(regInfo.VertexBufferObject !=null
    //                //{

    //                //    //regInfo.VertexData = regInfo.GetVertices()();
    //                //    //regInfo.VertexCopyLength = regInfo.GetVertices()Count();
    //                //    //newCount = regInfo.GetVertices()Count();
    //                //}

    //                //regInfo.VertexBufferChanged = true;
    //            }
    //            else
    //            {
    //                int iLockOffset = (int)regInfo.LockOffsetIntoVertexBuffer;

    //                //test lock then unlock--in past code this was reversed.
    //                mVertexBuffer.Unlock();
    //                mVertexBuffer.SetData(regInfo.VertexData, iLockOffset, LockFlags.ReadOnly);
    //                mVertexBuffer.Lock(iLockOffset, regInfo.VertexData.Length, LockFlags.ReadOnly);
    //            }
    //        }
    //    //}

    //} //end of procedure

    /*
    /// <summary>
    /// Meat of the renderer. Recreate the vertex array in the order the items were made.
    /// This method can be called to initialize the structure as well as to maintain it.
    /// Note to self: be sure to add references to:
    ///   InitialLength ScaleFactor 
    /// </summary>
    private void RecreateIndexArray()
    {
        int offsetIndex = 0;
        int blockIndex = 0; //of theoretical value

        RegistrationInfo[] regInfoList = GetRegistrationsArray(); //primitiveWithVertices registration list
        //int finalSize = -1;
        //bool willChange = WillIBChange(regInfoList, out finalSize);

        //remember adding zero to something does no point so sometimes that's easy to forget if you dont see me add a length to the accumulator.
        if (regInfoList != null && regInfoList.Count() != 0)
        { //Signaling that the array needs to be recreated...

            //aDataIndices = new int[finalSize];

            //NOW CREATE THE DATA...COPY DATA PROCESS
            foreach (RegistrationInfo regInfo in regInfoList)
            {
                if (regInfo == null)
                { //Null pointer. skip past this element; not copying it into the new array
                }
                else
                {
                    int[] idxData;
                    if (regInfo.IndexedBufferObject!=null )
                    {
                        idxData = regInfo.IndexedBufferObject.GetIndices();
                        regInfo.IndexCopyLength = idxData.Length;
                        regInfo.CurrentIndexBufferLength = idxData.Length;
                        offsetIndex += regInfo.CurrentIndexBufferLength;
                          
                    }
                }
                blockIndex++;
            }
        } //end of if.


    } //end of procedure.
    */
	
    #endregion //"Old Code"
//OLD CODE

} //end of class.

	public class PrimitiveNotRegisteredException : Exception
	{
		public object FailedPrimitive;
		public PrimitiveNotRegisteredException(object o)
		{
			FailedPrimitive = o;
			//"PrimitiveGenerator : " + " ( " + pg.ToString() + ") not registered! Cannot access registration info.";
		}
	}


}

